package cn.tqfeiyang.smartadmin.system.service;

import cn.tqfeiyang.smartadmin.commons.exception.BusinessException;
import cn.tqfeiyang.smartadmin.commons.pagination.PageData;
import cn.tqfeiyang.smartadmin.commons.pagination.QueryParams;
import cn.tqfeiyang.smartadmin.commons.toolbox.BeanUtils;
import cn.tqfeiyang.smartadmin.commons.toolbox.CollectionUtils;
import cn.tqfeiyang.smartadmin.commons.toolbox.ValidationUtils;
import cn.tqfeiyang.smartadmin.system.entity.MenuEntity;
import cn.tqfeiyang.smartadmin.system.entity.PermissionEntity;
import cn.tqfeiyang.smartadmin.system.entity.RoleEntity;
import cn.tqfeiyang.smartadmin.system.entity.UserEntity;
import cn.tqfeiyang.smartadmin.system.mapper.RoleMapper;
import cn.tqfeiyang.smartadmin.system.mapper.RoleMenuMapper;
import cn.tqfeiyang.smartadmin.system.mapper.RolePermissionMapper;
import cn.tqfeiyang.smartadmin.system.mapper.UserRoleMapper;
import cn.tqfeiyang.smartadmin.system.request.RoleCreateDTO;
import cn.tqfeiyang.smartadmin.system.request.RoleQueryDTO;
import cn.tqfeiyang.smartadmin.system.request.RoleUpdateDTO;
import cn.tqfeiyang.smartadmin.system.response.*;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.github.pagehelper.PageHelper;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.util.List;
import java.util.Set;

/**
 * 角色服务
 *
 * @author tqfeiyang
 * @since 2024/8/20 14:20
 */
@Service
public class RoleService {

    /**
     * 角色映射接口
     */
    @Resource
    private RoleMapper roleMapper;

    /**
     * 角色-菜单映射接口
     */
    @Resource
    private RoleMenuMapper roleMenuMapper;

    /**
     * 角色-权限映射接口
     */
    @Resource
    private RolePermissionMapper rolePermissionMapper;

    /**
     * 用户-角色映射接口
     */
    @Resource
    private UserRoleMapper userRoleMapper;

    /**
     * 查询角色
     *
     * @param dto 请求数据
     * @return 角色列表
     */
    public PageData<RoleQueryVO> queryRoles(RoleQueryDTO dto) {
        ValidationUtils.validateProperties(dto);
        PageHelper.startPage(dto.getPageNum(), dto.getPageSize());
        List<RoleEntity> list = roleMapper.selectList(dto.getWrapper());
        return PageData.create(list, RoleQueryVO.class);
    }

    /**
     * 获取角色
     *
     * @param roleId 角色id
     * @return 角色信息
     */
    public RoleDetailVO readRole(Long roleId) {
        RoleEntity roleEntity = checkRoleExists(roleId);
        return BeanUtils.map(roleEntity, RoleDetailVO.class);
    }

    /**
     * 添加角色
     *
     * @param dto 请求数据
     * @return 角色id
     */
    @Transactional(rollbackFor = Exception.class)
    public Long createRole(RoleCreateDTO dto) {
        ValidationUtils.validateProperties(dto);

        if (checkColumnExists("code", dto.getCode(), null)) {
            throw new BusinessException("角色编码已经存在");
        }

        if (checkColumnExists("name", dto.getName(), null)) {
            throw new BusinessException("角色名称已经存在");
        }

        RoleEntity insertedEntity = BeanUtils.copy(dto, RoleEntity.class);
        roleMapper.insert(insertedEntity);
        return insertedEntity.getRoleId();
    }

    /**
     * 修改角色
     *
     * @param roleId 角色id
     * @param dto 请求数据
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateRole(Long roleId, RoleUpdateDTO dto) {
        checkRoleExists(roleId);
        ValidationUtils.validateProperties(dto);

        if (dto.getCode() != null) {
            if (checkColumnExists("code", dto.getCode(), roleId)) {
                throw new BusinessException("角色编码已经存在");
            }
        }

        if (dto.getName() != null) {
            if (checkColumnExists("name", dto.getName(), roleId)) {
                throw new BusinessException("角色名称已经存在");
            }
        }

        RoleEntity updatedEntity = BeanUtils.copy(dto, RoleEntity.class);
        updatedEntity.setRoleId(roleId);
        roleMapper.updateById(updatedEntity);
    }

    /**
     * 删除角色
     *
     * @param roleId 角色id
     */
    @Transactional(rollbackFor = Exception.class)
    public void deleteRole(Long roleId) {
        checkRoleExists(roleId);
        roleMapper.deleteById(roleId);
        roleMenuMapper.deleteMenuIdsByRoleId(roleId);
        rolePermissionMapper.deletePermissionIdsByRoleId(roleId);
        userRoleMapper.deleteUserIdsByRoleId(roleId);
    }

    /**
     * 检查角色实体是否存在
     *
     * @param roleId 角色id
     */
    private RoleEntity checkRoleExists(Long roleId) {
        Assert.notNull(roleId, "roleId不能为空");
        RoleEntity roleEntity = roleMapper.selectById(roleId);
        if (ObjectUtils.isEmpty(roleEntity)) {
            throw new BusinessException("角色不存在");
        }
        return roleEntity;
    }

    /**
     * 检查字段值是否已经存在
     *
     * @param column 字段名
     * @param value  字段值
     * @param excludeId 需要排除的id
     * @return 如果字段值已经存在，返回 true，否则返回 false。
     */
    private boolean checkColumnExists(String column, String value, Long excludeId) {
        QueryWrapper<RoleEntity> wrapper = new QueryWrapper<>();
        wrapper.eq(column, value);

        if (excludeId != null) {
            wrapper.ne("role_id", excludeId);
        }

        RoleEntity roleEntity = roleMapper.selectOne(wrapper);
        return ObjectUtils.isNotEmpty(roleEntity);
    }

    /**
     * 查询菜单
     *
     * @param roleId 角色id
     * @param dto 请求数据
     * @return 菜单列表
     */
    public PageData<MenuQueryVO> queryMenus(Long roleId, QueryParams dto) {
        checkRoleExists(roleId);
        ValidationUtils.validateProperties(dto);
        PageHelper.startPage(dto.getPageNum(), dto.getPageSize());
        List<MenuEntity> list = roleMenuMapper.selectMenuListByRoleId(roleId);
        return PageData.create(list, MenuQueryVO.class);
    }

    /**
     * 更新菜单
     *
     * @param roleId 角色id
     * @param menuIds 菜单id集合
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateMenus(Long roleId, Set<Long> menuIds) {
        checkRoleExists(roleId);
        roleMenuMapper.deleteMenuIdsByRoleId(roleId);
        if (CollectionUtils.isNotEmpty(menuIds)) {
            roleMenuMapper.insertMenuIdsByRoleId(roleId, menuIds);
        }
    }

    /**
     * 查询权限
     *
     * @param roleId 角色id
     * @param dto 请求数据
     * @return 权限列表
     */
    public PageData<PermissionQueryVO> queryPermissions(Long roleId, QueryParams dto) {
        checkRoleExists(roleId);
        ValidationUtils.validateProperties(dto);
        PageHelper.startPage(dto.getPageNum(), dto.getPageSize());
        List<PermissionEntity> list = rolePermissionMapper.selectPermissionListByRoleId(roleId);
        return PageData.create(list, PermissionQueryVO.class);
    }

    /**
     * 更新权限
     *
     * @param roleId 角色id
     * @param menuIds 权限id集合
     */
    @Transactional(rollbackFor = Exception.class)
    public void updatePermissions(Long roleId, Set<Long> menuIds) {
        checkRoleExists(roleId);
        rolePermissionMapper.deletePermissionIdsByRoleId(roleId);
        if (CollectionUtils.isNotEmpty(menuIds)) {
            rolePermissionMapper.insertPermissionIdsByRoleId(roleId, menuIds);
        }
    }

    /**
     * 查询用户
     *
     * @param roleId 角色id
     * @param dto 请求数据
     * @return 用户列表
     */
    public PageData<UserQueryVO> queryUsers(Long roleId, QueryParams dto) {
        checkRoleExists(roleId);
        ValidationUtils.validateProperties(dto);
        PageHelper.startPage(dto.getPageNum(), dto.getPageSize());
        List<UserEntity> list = userRoleMapper.selectUserListByRoleId(roleId);
        return PageData.create(list, UserQueryVO.class);
    }

    /**
     * 更新用户
     *
     * @param roleId 角色id
     * @param userIds 用户id集合
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateUsers(Long roleId, Set<Long> userIds) {
        checkRoleExists(roleId);
        userRoleMapper.deleteUserIdsByRoleId(roleId);
        if (CollectionUtils.isNotEmpty(userIds)) {
            userRoleMapper.insertUserIdsByRoled(roleId, userIds);
        }
    }
}
